home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / GUSI-RPC 4.0 / clnt_udp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-17  |  11.9 KB  |  452 lines  |  [TEXT/MPS ]

  1. /* @(#)clnt_udp.c    2.2 88/08/01 4.0 RPCSRC */
  2. /*
  3.  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
  4.  * unrestricted use provided that this legend is included on all tape
  5.  * media and as a part of the software program in whole or part.  Users
  6.  * may copy or modify Sun RPC without charge, but are not authorized
  7.  * to license or distribute it to anyone else except as part of a product or
  8.  * program developed by the user.
  9.  * 
  10.  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  11.  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  12.  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  13.  * 
  14.  * Sun RPC is provided with no support and without any obligation on the
  15.  * part of Sun Microsystems, Inc. to assist in its use, correction,
  16.  * modification or enhancement.
  17.  * 
  18.  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  19.  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
  20.  * OR ANY PART THEREOF.
  21.  * 
  22.  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  23.  * or profits or other special, indirect and consequential damages, even if
  24.  * Sun has been advised of the possibility of such damages.
  25.  * 
  26.  * Sun Microsystems, Inc.
  27.  * 2550 Garcia Avenue
  28.  * Mountain View, California  94043
  29.  */
  30. #if !defined(lint) && defined(SCCSIDS)
  31. static char sccsid[] = "@(#)clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro";
  32. #endif
  33.  
  34. /*
  35.  * clnt_udp.c, Implements a UDP/IP based, client side RPC.
  36.  *
  37.  * Copyright (C) 1984, Sun Microsystems, Inc.
  38.  */
  39.  
  40. #include <stdio.h>
  41. #include <rpc/rpc.h>
  42. #include <sys/socket.h>
  43. #include <sys/ioctl.h>
  44. #include <netdb.h>
  45. #include <sys/errno.h>
  46. #include <rpc/pmap_clnt.h>
  47.  
  48. extern int errno;
  49.  
  50. /*
  51.  * UDP bases client side rpc operations
  52.  */
  53. static enum clnt_stat    clntudp_call();
  54. static void        clntudp_abort();
  55. static void        clntudp_geterr();
  56. static bool_t        clntudp_freeres();
  57. static bool_t           clntudp_control();
  58. static void        clntudp_destroy();
  59.  
  60. static struct clnt_ops udp_ops = {
  61.     clntudp_call,
  62.     clntudp_abort,
  63.     clntudp_geterr,
  64.     clntudp_freeres,
  65.     clntudp_destroy,
  66.     clntudp_control
  67. };
  68.  
  69. /* 
  70.  * Private data kept per client handle
  71.  */
  72. struct cu_data {
  73.     int           cu_sock;
  74.     bool_t           cu_closeit;
  75.     struct sockaddr_in cu_raddr;
  76.     int           cu_rlen;
  77.     struct timeval       cu_wait;
  78.     struct timeval     cu_total;
  79.     struct rpc_err       cu_error;
  80.     XDR           cu_outxdrs;
  81.     u_int           cu_xdrpos;
  82.     u_int           cu_sendsz;
  83.     char           *cu_outbuf;
  84.     u_int           cu_recvsz;
  85.     char           cu_inbuf[1];
  86. };
  87.  
  88. /*
  89.  * Create a UDP based client handle.
  90.  * If *sockp<0, *sockp is set to a newly created UPD socket.
  91.  * If raddr->sin_port is 0 a binder on the remote machine
  92.  * is consulted for the correct port number.
  93.  * NB: It is the clients responsibility to close *sockp.
  94.  * NB: The rpch->cl_auth is initialized to null authentication.
  95.  *     Caller may wish to set this something more useful.
  96.  *
  97.  * wait is the amount of time used between retransmitting a call if
  98.  * no response has been heard;  retransmition occurs until the actual
  99.  * rpc call times out.
  100.  *
  101.  * sendsz and recvsz are the maximum allowable packet sizes that can be
  102.  * sent and received.
  103.  */
  104. CLIENT *
  105. clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz)
  106.     struct sockaddr_in *raddr;
  107.     u_long program;
  108.     u_long version;
  109.     struct timeval wait;
  110.     register int *sockp;
  111.     u_int sendsz;
  112.     u_int recvsz;
  113. {
  114.     CLIENT *cl;
  115.     register struct cu_data *cu;
  116. #if 0
  117.     struct timeval now;
  118. #else
  119.     time_t now;
  120. #endifÆ’
  121.     struct rpc_msg call_msg;
  122.  
  123.     cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
  124.     if (cl == NULL) {
  125.         (void) fprintf(stderr, "clntudp_create: out of memory\n");
  126.         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  127.         rpc_createerr.cf_error.re_errno = errno;
  128.         goto fooy;
  129.     }
  130.     sendsz = ((sendsz + 3) / 4) * 4;
  131.     recvsz = ((recvsz + 3) / 4) * 4;
  132.     cu = (struct cu_data *)mem_alloc(sizeof(*cu) + sendsz + recvsz);
  133.     if (cu == NULL) {
  134.         (void) fprintf(stderr, "clntudp_create: out of memory\n");
  135.         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  136.         rpc_createerr.cf_error.re_errno = errno;
  137.         goto fooy;
  138.     }
  139.     cu->cu_outbuf = &cu->cu_inbuf[recvsz];
  140.  
  141.     if (raddr->sin_port == 0) {
  142.         u_short port;
  143.         if ((port =
  144.             pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
  145.             goto fooy;
  146.         }
  147.         raddr->sin_port = htons(port);
  148.     }
  149.     cl->cl_ops = &udp_ops;
  150.     cl->cl_private = (caddr_t)cu;
  151.     cu->cu_raddr = *raddr;
  152.     cu->cu_rlen = sizeof (cu->cu_raddr);
  153.     cu->cu_wait = wait;
  154.     cu->cu_total.tv_sec = -1;
  155.     cu->cu_total.tv_usec = -1;
  156.     cu->cu_sendsz = sendsz;
  157.     cu->cu_recvsz = recvsz;
  158. #if 0
  159.     (void)gettimeofday(&now, (struct timezone *)0);
  160.     call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
  161. #else
  162.     (void) time(&now);
  163.     call_msg.rm_xid = getpid() ^ now;
  164. #endif
  165.     call_msg.rm_direction = CALL;
  166.     call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
  167.     call_msg.rm_call.cb_prog = program;
  168.     call_msg.rm_call.cb_vers = version;
  169.     xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf,
  170.         sendsz, XDR_ENCODE);
  171.     if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
  172.         goto fooy;
  173.     }
  174.     cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
  175.     if (*sockp < 0) {
  176.         int dontblock = 1;
  177.  
  178.         *sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  179.         if (*sockp < 0) {
  180.             rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  181.             rpc_createerr.cf_error.re_errno = errno;
  182.             goto fooy;
  183.         }
  184.         /* attempt to bind to prov port */
  185.         (void)bindresvport(*sockp, (struct sockaddr_in *)0);
  186.         /* the sockets rpc controls are non-blocking */
  187.         (void)ioctl(*sockp, FIONBIO, (long *) &dontblock);        /* XXXX */
  188.         cu->cu_closeit = TRUE;
  189.     } else {
  190.         cu->cu_closeit = FALSE;
  191.     }
  192.     cu->cu_sock = *sockp;
  193.     cl->cl_auth = authnone_create();
  194.     return (cl);
  195. fooy:
  196.     if (cu)
  197.         mem_free((caddr_t)cu, sizeof(*cu) + sendsz + recvsz);
  198.     if (cl)
  199.         mem_free((caddr_t)cl, sizeof(CLIENT));
  200.     return ((CLIENT *)NULL);
  201. }
  202.  
  203. CLIENT *
  204. clntudp_create(raddr, program, version, wait, sockp)
  205.     struct sockaddr_in *raddr;
  206.     u_long program;
  207.     u_long version;
  208.     struct timeval wait;
  209.     register int *sockp;
  210. {
  211.  
  212.     return(clntudp_bufcreate(raddr, program, version, wait, sockp,
  213.         UDPMSGSIZE, UDPMSGSIZE));
  214. }
  215.  
  216. static enum clnt_stat 
  217. clntudp_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout)
  218.     register CLIENT    *cl;        /* client handle */
  219.     u_long        proc;        /* procedure number */
  220.     xdrproc_t    xargs;        /* xdr routine for args */
  221.     caddr_t        argsp;        /* pointer to args */
  222.     xdrproc_t    xresults;    /* xdr routine for results */
  223.     caddr_t        resultsp;    /* pointer to results */
  224.     struct timeval    utimeout;    /* seconds to wait before giving up */
  225. {
  226.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  227.     register XDR *xdrs;
  228.     register int outlen;
  229.     register int inlen;
  230.     int fromlen;
  231. #ifdef FD_SETSIZE
  232.     fd_set readfds;
  233.     fd_set mask;
  234. #else
  235.     int readfds;
  236.     register int mask;
  237. #endif /* def FD_SETSIZE */
  238.     struct sockaddr_in from;
  239.     struct rpc_msg reply_msg;
  240.     XDR reply_xdrs;
  241.     struct timeval time_waited;
  242.     bool_t ok;
  243.     int nrefreshes = 2;    /* number of times to refresh cred */
  244.     struct timeval timeout;
  245.  
  246.     if (cu->cu_total.tv_usec == -1) {
  247.         timeout = utimeout;     /* use supplied timeout */
  248.     } else {
  249.         timeout = cu->cu_total; /* use default timeout */
  250.     }
  251.  
  252.     time_waited.tv_sec = 0;
  253.     time_waited.tv_usec = 0;
  254. call_again:
  255.     xdrs = &(cu->cu_outxdrs);
  256.     xdrs->x_op = XDR_ENCODE;
  257.     XDR_SETPOS(xdrs, cu->cu_xdrpos);
  258.     /*
  259.      * the transaction is the first thing in the out buffer
  260.      */
  261.     (*(u_short *)(cu->cu_outbuf))++;
  262.     if ((! XDR_PUTLONG(xdrs, (long *)&proc)) ||
  263.         (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
  264.         (! (*xargs)(xdrs, argsp)))
  265.         return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
  266.     outlen = (int)XDR_GETPOS(xdrs);
  267.  
  268. send_again:
  269.     if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0,
  270.         (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen)
  271.         != outlen) {
  272.         cu->cu_error.re_errno = errno;
  273.         return (cu->cu_error.re_status = RPC_CANTSEND);
  274.     }
  275.  
  276.     /*
  277.      * Hack to provide rpc-based message passing
  278.      */
  279.     if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
  280.         return (cu->cu_error.re_status = RPC_TIMEDOUT);
  281.     }
  282.     /*
  283.      * sub-optimal code appears here because we have
  284.      * some clock time to spare while the packets are in flight.
  285.      * (We assume that this is actually only executed once.)
  286.      */
  287.     reply_msg.acpted_rply.ar_verf = _null_auth;
  288.     reply_msg.acpted_rply.ar_results.where = resultsp;
  289.     reply_msg.acpted_rply.ar_results.proc = xresults;
  290. #ifdef FD_SETSIZE
  291.     FD_ZERO(&mask);
  292.     FD_SET(cu->cu_sock, &mask);
  293. #else
  294.     mask = 1 << cu->cu_sock;
  295. #endif /* def FD_SETSIZE */
  296.     for (;;) {
  297.         readfds = mask;
  298.         switch (select(_rpc_dtablesize(), &readfds, (fd_set *)NULL, 
  299.                    (fd_set *)NULL, &(cu->cu_wait))) {
  300.  
  301.         case 0:
  302.             time_waited.tv_sec += cu->cu_wait.tv_sec;
  303.             time_waited.tv_usec += cu->cu_wait.tv_usec;
  304.             while (time_waited.tv_usec >= 1000000) {
  305.                 time_waited.tv_sec++;
  306.                 time_waited.tv_usec -= 1000000;
  307.             }
  308.             if ((time_waited.tv_sec < timeout.tv_sec) ||
  309.                 ((time_waited.tv_sec == timeout.tv_sec) &&
  310.                 (time_waited.tv_usec < timeout.tv_usec)))
  311.                 goto send_again;    
  312.             return (cu->cu_error.re_status = RPC_TIMEDOUT);
  313.  
  314.         /*
  315.          * buggy in other cases because time_waited is not being
  316.          * updated.
  317.          */
  318.         case -1:
  319.             if (errno == EINTR)
  320.                 continue;    
  321.             cu->cu_error.re_errno = errno;
  322.             return (cu->cu_error.re_status = RPC_CANTRECV);
  323.         }
  324.         do {
  325.             fromlen = sizeof(struct sockaddr);
  326.             inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, 
  327.                 (int) cu->cu_recvsz, 0,
  328.                 (struct sockaddr *)&from, &fromlen);
  329.         } while (inlen < 0 && errno == EINTR);
  330.         if (inlen < 0) {
  331.             if (errno == EWOULDBLOCK)
  332.                 continue;    
  333.             cu->cu_error.re_errno = errno;
  334.             return (cu->cu_error.re_status = RPC_CANTRECV);
  335.         }
  336.         if (inlen < sizeof(u_long))
  337.             continue;    
  338.         /* see if reply transaction id matches sent id */
  339.         if (*((u_long *)(cu->cu_inbuf)) != *((u_long *)(cu->cu_outbuf)))
  340.             continue;    
  341.         /* we now assume we have the proper reply */
  342.         break;
  343.     }
  344.  
  345.     /*
  346.      * now decode and validate the response
  347.      */
  348.     xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE);
  349.     ok = xdr_replymsg(&reply_xdrs, &reply_msg);
  350.     /* XDR_DESTROY(&reply_xdrs);  save a few cycles on noop destroy */
  351.     if (ok) {
  352.         _seterr_reply(&reply_msg, &(cu->cu_error));
  353.         if (cu->cu_error.re_status == RPC_SUCCESS) {
  354.             if (! AUTH_VALIDATE(cl->cl_auth,
  355.                 &reply_msg.acpted_rply.ar_verf)) {
  356.                 cu->cu_error.re_status = RPC_AUTHERROR;
  357.                 cu->cu_error.re_why = AUTH_INVALIDRESP;
  358.             }
  359.             if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
  360.                 xdrs->x_op = XDR_FREE;
  361.                 (void)xdr_opaque_auth(xdrs,
  362.                     &(reply_msg.acpted_rply.ar_verf));
  363.             } 
  364.         }  /* end successful completion */
  365.         else {
  366.             /* maybe our credentials need to be refreshed ... */
  367.             if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) {
  368.                 nrefreshes--;
  369.                 goto call_again;
  370.             }
  371.         }  /* end of unsuccessful completion */
  372.     }  /* end of valid reply message */
  373.     else {
  374.         cu->cu_error.re_status = RPC_CANTDECODERES;
  375.     }
  376.     return (cu->cu_error.re_status);
  377. }
  378.  
  379. static void
  380. clntudp_geterr(cl, errp)
  381.     CLIENT *cl;
  382.     struct rpc_err *errp;
  383. {
  384.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  385.  
  386.     *errp = cu->cu_error;
  387. }
  388.  
  389.  
  390. static bool_t
  391. clntudp_freeres(cl, xdr_res, res_ptr)
  392.     CLIENT *cl;
  393.     xdrproc_t xdr_res;
  394.     caddr_t res_ptr;
  395. {
  396.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  397.     register XDR *xdrs = &(cu->cu_outxdrs);
  398.  
  399.     xdrs->x_op = XDR_FREE;
  400.     return ((*xdr_res)(xdrs, res_ptr));
  401. }
  402.  
  403. static void 
  404. clntudp_abort(/*h*/)
  405.     /*CLIENT *h;*/
  406. {
  407. }
  408.  
  409. static bool_t
  410. clntudp_control(cl, request, info)
  411.     CLIENT *cl;
  412.     int request;
  413.     char *info;
  414. {
  415.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  416.  
  417.     switch (request) {
  418.     case CLSET_TIMEOUT:
  419.         cu->cu_total = *(struct timeval *)info;
  420.         break;
  421.     case CLGET_TIMEOUT:
  422.         *(struct timeval *)info = cu->cu_total;
  423.         break;
  424.     case CLSET_RETRY_TIMEOUT:
  425.         cu->cu_wait = *(struct timeval *)info;
  426.         break;
  427.     case CLGET_RETRY_TIMEOUT:
  428.         *(struct timeval *)info = cu->cu_wait;
  429.         break;
  430.     case CLGET_SERVER_ADDR:
  431.         *(struct sockaddr_in *)info = cu->cu_raddr;
  432.         break;
  433.     default:
  434.         return (FALSE);
  435.     }
  436.     return (TRUE);
  437. }
  438.     
  439. static void
  440. clntudp_destroy(cl)
  441.     CLIENT *cl;
  442. {
  443.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  444.  
  445.     if (cu->cu_closeit) {
  446.         (void)close(cu->cu_sock);
  447.     }
  448.     XDR_DESTROY(&(cu->cu_outxdrs));
  449.     mem_free((caddr_t)cu, (sizeof(*cu) + cu->cu_sendsz + cu->cu_recvsz));
  450.     mem_free((caddr_t)cl, sizeof(CLIENT));
  451. }
  452.